﻿using System.Collections.Generic;

namespace Core
{
    public sealed class TaskQueue<T>
        where T : AbstractTask
    {
        private readonly LinkedList<T> workingList = new();
        private readonly LinkedList<T> waitingList = new();

        /// <summary>
        /// 并发数量，可以同时处理的
        /// </summary>
        public int Concurrency { get; private set; }

        public TaskQueue(int concurrency)
        {
            Concurrency = concurrency;
        }

        public bool Paused { get; set; }

        /// <summary>
        /// 总数量 = 正在处理 + 等待处理
        /// </summary>
        public int TotalCount => WorkingCount + WaitingCount;

        /// <summary>
        /// 正在处理的数量
        /// </summary>
        public int WorkingCount => workingList.Count;

        /// <summary>
        /// 等待处理
        /// </summary>
        public int WaitingCount => waitingList.Count;

        public void Update()
        {
            if (Paused) return;

            RunningUpdate();
            WaitingUpdate();
        }

        public void Add(T task)
        {
            if (WorkingCount < Concurrency)
            {
                task.Start();
                workingList.AddLast(task);
            }
            else
            {
                waitingList.AddLast(task);
            }
        }

        public bool Remove(long taskID)
        {
            foreach (var task in waitingList)
            {
                if (task.InstanceId == taskID)
                {
                    waitingList.Remove(task);
                    task.Dispose();
                    return true;
                }
            }

            foreach (var task in workingList)
            {
                if (task.InstanceId == taskID)
                {
                    workingList.Remove(task);
                    task.Dispose();
                    return true;
                }
            }

            return false;
        }

        public T Get(long taskID)
        {
            foreach (var task in waitingList)
            {
                if (task.InstanceId == taskID)
                {
                    return task;
                }
            }

            foreach (var task in workingList)
            {
                if (task.InstanceId == taskID)
                {
                    return task;
                }
            }

            return null;
        }

        public void RemoveAll()
        {
            foreach (var task in waitingList)
            {
                task.Dispose();
            }

            waitingList.Clear();

            foreach (var task in workingList)
            {
                task.Dispose();
            }

            workingList.Clear();
        }

        private void RunningUpdate()
        {
            var current = workingList.First;
            while (current != null)
            {
                var task = current.Value;
                if (task.Status == ETaskStatus.Doing)
                {
                    task.Update();
                }

                if (task.Status == ETaskStatus.Doing)
                {
                    current = current.Next;
                    continue;
                }

                task.Finish();

                var next = current.Next;
                workingList.Remove(current);
                task.Dispose();
                current = next;
            }
        }

        private void WaitingUpdate()
        {
            var current = waitingList.First;

            while (current != null && WorkingCount < Concurrency)
            {
                var next = current.Next;

                T task = current.Value;
                workingList.AddLast(task);
                task.Start();
                waitingList.Remove(task);

                current = next;
            }
        }
    }
}
